package com.dlc.shop.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dlc.shop.allinpay.service.AllinpayCompanyService;
import com.dlc.shop.allinpay.service.AllinpayService;
import com.dlc.shop.bean.dto.ShopWithdrawCashConfigDto;
import com.dlc.shop.bean.dto.allinpay.AllinpayShopWithdrawCashDTO;
import com.dlc.shop.bean.enums.SendType;
import com.dlc.shop.bean.enums.ShopWalletChangeReason;
import com.dlc.shop.bean.enums.ShopWithdrawCashStatus;
import com.dlc.shop.bean.enums.WithdrawCashEnum;
import com.dlc.shop.bean.event.GetShopSupperAdminEvent;
import com.dlc.shop.bean.model.ShopDetail;
import com.dlc.shop.bean.model.ShopWallet;
import com.dlc.shop.bean.model.ShopWithdrawCash;
import com.dlc.shop.common.allinpay.constant.*;
import com.dlc.shop.common.allinpay.member.constant.VisitSourceType;
import com.dlc.shop.common.allinpay.member.resp.BindCard;
import com.dlc.shop.common.allinpay.order.req.PayByBackSmsReq;
import com.dlc.shop.common.allinpay.order.resp.PayByBackSmsResp;
import com.dlc.shop.common.allinpay.order.resp.ResendPaySmsResp;
import com.dlc.shop.common.allinpay.order.resp.WithdrawApplyResp;
import com.dlc.shop.common.bean.SysConfig;
import com.dlc.shop.common.config.Constant;
import com.dlc.shop.common.constants.SegmentIdKey;
import com.dlc.shop.common.enums.SysTypeEnum;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.i18n.I18nMessage;
import com.dlc.shop.common.util.*;
import com.dlc.shop.config.ShopConfig;
import com.dlc.shop.dao.EnterprisePayMapper;
import com.dlc.shop.dao.ShopWithdrawCashMapper;
import com.dlc.shop.manager.impl.AllinpayManager;
import com.dlc.shop.service.*;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import org.apache.poi.ss.usermodel.Sheet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 商家提现申请信息
 *
 * @author
 * @date 2019-09-19 14:22:08
 */
@Service
@AllArgsConstructor
public class ShopWithdrawCashServiceImpl extends ServiceImpl<ShopWithdrawCashMapper, ShopWithdrawCash> implements ShopWithdrawCashService {
    private static final Logger logger = LoggerFactory.getLogger(ShopWithdrawCashServiceImpl.class);

    private final ShopWithdrawCashMapper shopWithdrawCashMapper;
    private final ShopWalletLogService shopWalletLogService;
    private final ShopWalletService shopWalletService;
    private final ShopDetailService shopDetailService;
    private final EnterprisePayMapper enterprisePayMapper;
    private final SmsLogService smsLogService;
    private final SysConfigService sysConfigService;
    private final AllinpayCompanyService allinpayCompanyService;
    private final SegmentService segmentService;
    private final AllinpayManager allinpayManager;
    private final AllinpayService allinpayService;
    private final ShopConfig shopConfig;
    private final ApplicationContext applicationContext;
    private final String SHOP_WITHDRAW_CASH_PREFIX = "ShopWithdrawCash_";

    /**
     * 导出excel列
     */
    private final static String[] EXPORT_COL = {
            I18nMessage.getMessage("yami.shop.withdraw.cash.excel.header.shopName"),
            I18nMessage.getMessage("yami.shop.withdraw.cash.excel.header.cash"),
            I18nMessage.getMessage("yami.shop.withdraw.cash.excel.header.createTime"),
            I18nMessage.getMessage("yami.shop.withdraw.cash.excel.header.updateTime"),
            I18nMessage.getMessage("yami.shop.withdraw.cash.excel.header.auditTime"),
            I18nMessage.getMessage("yami.shop.withdraw.cash.excel.header.auditStatus")
    };

    /**
     * 通联导出excel列
     */
    private final static String[] EXPORT_COL_ALLINPAY = {
            I18nMessage.getMessage("yami.shop.withdraw.cash.excel.header.shopName"),
            I18nMessage.getMessage("yami.shop.withdraw.cash.excel.header.cash"),
            I18nMessage.getMessage("yami.shop.withdraw.cash.excel.header.createTime"),
            I18nMessage.getMessage("yami.shop.withdraw.cash.excel.header.updateTime")
    };

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void withdrawCash(ShopWithdrawCash shopWithdrawCash) {
        Integer paySysType = allinpayCompanyService.getIsAllinpay() ? PaySysType.ALLINPAY.value() : PaySysType.DEFAULT.value();
        Long shopId = shopWithdrawCash.getShopId();
        GetShopSupperAdminEvent event = new GetShopSupperAdminEvent(shopId);
        applicationContext.publishEvent(event);
        if (!smsLogService.checkValidCode(event.getMobile(), shopWithdrawCash.getCode(), SendType.CAPTCHA)) {
            // 验证码有误或已过期
            throw new YamiShopBindException("yami.user.code.error");
        }
        ShopWallet dbShopWallet = shopWalletService.getShopWalletByShopId(shopId);
        if (shopWithdrawCash.getAmount() > dbShopWallet.getSettledAmount()) {
            // 可提现金额不足
            throw new YamiShopBindException("yami.shop.cash.no.enough");
        }
        checkConfig(shopWithdrawCash);
        shopWithdrawCash.setPaySysType(paySysType);
        // 更新钱包，添加提现日志
        changeWalletAndAddLog(shopWithdrawCash, dbShopWallet);
    }

    private void changeWalletAndAddLog(ShopWithdrawCash shopWithdrawCash, ShopWallet dbShopWallet) {
        shopWithdrawCash.setCreateTime(new Date());
        shopWithdrawCash.setUpdateTime(new Date());
        // 插入提现申请记录
        shopWithdrawCashMapper.insert(shopWithdrawCash);
        // 更新钱包，添加提现日志
        ShopWallet newShopWallet = BeanUtil.map(dbShopWallet, ShopWallet.class);
        newShopWallet.setSettledAmount(Arith.sub(dbShopWallet.getSettledAmount(), shopWithdrawCash.getAmount()));
        newShopWallet.setFreezeAmount(Arith.add(dbShopWallet.getFreezeAmount(), shopWithdrawCash.getAmount()));

        // 乐观锁更新钱包信息
        if (!shopWalletService.updateById(newShopWallet)) {
            // 失败则抛异常
            // 服务器繁忙
            throw new YamiShopBindException("yami.network.busy");
        }
        // 提现记录
        shopWalletLogService.saveShopWalletLog(dbShopWallet, newShopWallet, ShopWalletChangeReason.APPLY_CASH, null);
    }

    private void checkConfig(ShopWithdrawCash shopWithdrawCash) {
        ShopWithdrawCashConfigDto config = getConfig();
        if (shopWithdrawCash.getAmount() < config.getWithdrawCashLeast()) {
            throw new YamiShopBindException("提现金额过少，最低提现:" + config.getWithdrawCashLeast());
        }
        if (Objects.nonNull(config.getWithdrawCashMax()) && shopWithdrawCash.getAmount() > config.getWithdrawCashMax()) {
            throw new YamiShopBindException("提现金额过大,最高提现:" + config.getWithdrawCashMax());
        }
        Integer frequency = config.getFrequency();
        Date startTimes;
        Date endTimes;
        String date;
        if (frequency.equals(WithdrawCashEnum.WEEKEND.value())) {
            startTimes = DateUtils.getCurrentWeekStartTimes(new Date());
            endTimes = DateUtils.getCurrentWeekEndTimes(new Date());
            date = WithdrawCashEnum.WEEKEND.date();
        } else if (frequency.equals(WithdrawCashEnum.MONTH.value())) {
            startTimes = DateUtils.getMonthFirstOrLastDay(new Date(), 0);
            endTimes = DateUtils.getMonthFirstOrLastDay(new Date(), 1);
            date = WithdrawCashEnum.MONTH.date();
        } else {
            startTimes = DateUtils.getCurrentYearStartTime(new Date());
            endTimes = DateUtils.getCurrentYearEndTime(new Date());
            date = WithdrawCashEnum.YEAR.date();
        }
        long count = checkCount(startTimes, endTimes, shopWithdrawCash);
        if (count + 1 > config.getNumber()) {
            throw new YamiShopBindException("超出提现频率限制,当前提现频率为:" + date + " " + config.getNumber() + "次");
        }
    }

    private long checkCount(Date startTime, Date endTime, ShopWithdrawCash shopWithdrawCash) {
        return shopWithdrawCashMapper.selectCount(Wrappers.lambdaQuery(ShopWithdrawCash.class)
                .eq(ShopWithdrawCash::getShopId, shopWithdrawCash.getShopId())
                .ge(ShopWithdrawCash::getCreateTime, startTime)
                .le(ShopWithdrawCash::getCreateTime, endTime));
    }

    @Override
    public IPage<ShopWithdrawCash> pageShopWithdrawCash(PageParam<ShopWithdrawCash> page, ShopWithdrawCash shopWithdrawCash) {
        Integer paySysType = allinpayCompanyService.getIsAllinpay() ? PaySysType.ALLINPAY.value() : PaySysType.DEFAULT.value();
        shopWithdrawCash.setPaySysType(paySysType);
        return shopWithdrawCashMapper.pageShopWithdrawCash(page, shopWithdrawCash);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void auditWithdrawCash(Long withdrawCashId, ShopWithdrawCash shopWithdrawCash, Long userId, String openId) {
        if (allinpayCompanyService.getIsAllinpay()) {
            throw new YamiShopBindException("开启通联后，平台无需审核商家提现信息");
        }
        ShopWithdrawCash dbShopWithdrawCash = shopWithdrawCashMapper.selectById(withdrawCashId);
        if (!dbShopWithdrawCash.getStatus().equals(ShopWithdrawCashStatus.WAITAUDIT.value())) {
            // 该申请已被审核
            throw new YamiShopBindException("yami.examine.already");
        }
        Date now = new Date();
        dbShopWithdrawCash.setAuditingTime(now);
        dbShopWithdrawCash.setAuditorId(userId);
        dbShopWithdrawCash.setStatus(shopWithdrawCash.getStatus());
        dbShopWithdrawCash.setRemarks(shopWithdrawCash.getRemarks());
        dbShopWithdrawCash.setPayingTime(shopWithdrawCash.getPayingTime());
        dbShopWithdrawCash.setPayingCardNo(shopWithdrawCash.getPayingCardNo());
        dbShopWithdrawCash.setPayingAccount(shopWithdrawCash.getPayingAccount());

        ShopWallet dbShopWallet = shopWalletService.getShopWalletByShopId(dbShopWithdrawCash.getShopId());
        ShopWallet newShopWallet = BeanUtil.map(dbShopWallet, ShopWallet.class);
        // 审核通过
        if (Objects.equals(shopWithdrawCash.getStatus(), 1)) {
            //减去冻结的金额
            newShopWallet.setFreezeAmount(Arith.sub(dbShopWallet.getFreezeAmount(), dbShopWithdrawCash.getAmount()));
            shopWalletLogService.saveShopWalletLog(dbShopWallet, newShopWallet, ShopWalletChangeReason.PASS_CASH, null);
        } else if (Objects.equals(shopWithdrawCash.getStatus(), -1)) {
            // 将冻结的金额返回到已结算金额
            newShopWallet.setSettledAmount(Arith.add(dbShopWallet.getSettledAmount(), dbShopWithdrawCash.getAmount()));
            newShopWallet.setFreezeAmount(Arith.sub(dbShopWallet.getFreezeAmount(), dbShopWithdrawCash.getAmount()));
            shopWalletLogService.saveShopWalletLog(dbShopWallet, newShopWallet, ShopWalletChangeReason.REFUSE_CASH, null);
        } else {
            // 审核状态有误
            throw new YamiShopBindException("yami.examine.status.error");
        }

        // 乐观锁更新钱包信息
        if (!shopWalletService.updateById(newShopWallet)) {
            // 失败则抛异常
            // 服务器繁忙
            throw new YamiShopBindException("yami.network.busy");
        }
        shopWithdrawCashMapper.updateById(dbShopWithdrawCash);
    }

    @Override
    public ShopWithdrawCash getShopWithdrawCashByShopId(Long shopId) {
        Integer paySysType = allinpayCompanyService.getIsAllinpay() ? PaySysType.ALLINPAY.value() : PaySysType.DEFAULT.value();
        return shopWithdrawCashMapper.getShopWithdrawCashByShopId(shopId, paySysType);
    }

    @Override
    public void exportShopWithdrawCash(ShopWithdrawCash shopWithdrawCash, HttpServletResponse response) {
        Integer paySysType = allinpayCompanyService.getIsAllinpay() ? PaySysType.ALLINPAY.value() : PaySysType.DEFAULT.value();
        shopWithdrawCash.setPaySysType(paySysType);
        List<ShopWithdrawCash> shopWithdrawCashList = shopWithdrawCashMapper.listExportByParam(shopWithdrawCash);
        if (CollUtil.isEmpty(shopWithdrawCashList)) {
            return;
        }
        ExcelWriter writer = ExcelUtil.getBigWriter();
        List<String> exportCol = Arrays.asList(EXPORT_COL);
        if (Objects.equals(paySysType, PaySysType.ALLINPAY.value())) {
            exportCol = Arrays.asList(EXPORT_COL_ALLINPAY);
        }
        // 最大列数量
        int maxColNum = exportCol.size();

        Sheet sheet = writer.getSheet();
        //设置列宽
        this.setColumnWidth(sheet);
        // 标题
        writer.merge(maxColNum - 1, I18nMessage.getMessage("yami.shop.withdraw.cash.excel.title"));
        // 列名
        writer.writeRow(exportCol);
        int rowIndex = 2;
        for (ShopWithdrawCash withdrawCash : shopWithdrawCashList) {
            int col = -1;
            // 店铺名称
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, withdrawCash.getShopName());
            // 提现金额
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, withdrawCash.getAmount());
            // 创建时间
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, withdrawCash.getCreateTime());
            // 更新时间
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, withdrawCash.getUpdateTime());
            if (Objects.equals(paySysType, PaySysType.DEFAULT.value())) {
                // 审核时间
                PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, withdrawCash.getAuditingTime());
                // 审核状态
                ShopWithdrawCashStatus shopWithdrawCashStatus = ShopWithdrawCashStatus.instance(withdrawCash.getStatus());
                PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, Objects.isNull(shopWithdrawCashStatus) ? "" : shopWithdrawCashStatus.text());
            }

            ++rowIndex;
        }
        PoiExcelUtil.writeExcel(response, writer);
    }

    @Override
    public void saveConfig(ShopWithdrawCashConfigDto shopWithdrawCashDto) {
        checkParam(shopWithdrawCashDto);
        SysConfig sysConfig = new SysConfig();
        sysConfig.setRemark("提现配置");
        sysConfig.setParamValue(Json.toJsonString(shopWithdrawCashDto));
        sysConfig.setParamKey(Constant.WITHDRAW_CONFIG);
        sysConfigService.saveOrUpdateSysConfigByKey(sysConfig);
    }

    private void checkParam(ShopWithdrawCashConfigDto shopWithdrawCashDto) {
        Double least = shopWithdrawCashDto.getWithdrawCashLeast();
        Double max = shopWithdrawCashDto.getWithdrawCashMax();
        Integer frequency = shopWithdrawCashDto.getFrequency();
        Integer number = shopWithdrawCashDto.getNumber();
        if (Objects.isNull(least)) {
            throw new YamiShopBindException("yami.withdraw.amount.min.null");
        }
        if (least < Constant.MIN_WITHDRAW_CASH) {
            throw new YamiShopBindException(String.format(I18nMessage.getMessage("yami.withdraw.amount.min.error"), Constant.MIN_WITHDRAW_CASH));
        }
        if (Objects.nonNull(max) && max < least) {
            throw new YamiShopBindException("yami.withdraw.amount.max.error");
        }
        if (Objects.isNull(frequency)) {
            throw new YamiShopBindException("yami.withdraw.frequency.null");
        }
        boolean check = !frequency.equals(WithdrawCashEnum.WEEKEND.value()) && !frequency.equals(WithdrawCashEnum.MONTH.value()) && !frequency.equals(WithdrawCashEnum.YEAR.value());
        if (check) {
            throw new YamiShopBindException("yami.withdraw.frequency.error");
        }
        if(Objects.isNull(number)){
            throw new YamiShopBindException("yami.withdraw.number.null");
        }
        if (number < Constant.MIN_WITHDRAW_TIMES) {
            throw new YamiShopBindException(String.format(I18nMessage.getMessage("yami.withdraw.number.error"), Constant.MIN_WITHDRAW_TIMES));
        }
    }

    @Override
    public ShopWithdrawCashConfigDto getConfig() {
        ShopWithdrawCashConfigDto shopWithdrawCashConfigDto = sysConfigService.getSysConfigObject(Constant.WITHDRAW_CONFIG, ShopWithdrawCashConfigDto.class);
        if (Objects.isNull(shopWithdrawCashConfigDto)) {
            shopWithdrawCashConfigDto = new ShopWithdrawCashConfigDto();
            shopWithdrawCashConfigDto.setWithdrawCashLeast(100D);
            shopWithdrawCashConfigDto.setFrequency(1);
            shopWithdrawCashConfigDto.setNumber(1);
        }
        return shopWithdrawCashConfigDto;
    }

    private void setColumnWidth(Sheet sheet) {
        int column = 5;
        for (int i = 0; i <= column; i++) {
            sheet.setColumnWidth(i, 20 * 256);
        }
    }

    @Override
    public String allinpayApply(AllinpayShopWithdrawCashDTO allinpayShopWithdrawCashDTO, Long shopId) {
        Double amount = allinpayShopWithdrawCashDTO.getAmount();
        // 校验提现条件
        this.checkAllinpay(shopId, amount);
        ShopWithdrawCash shopWithdrawCash = new ShopWithdrawCash();
        shopWithdrawCash.setAmount(amount);
        shopWithdrawCash.setShopId(shopId);
        shopWithdrawCash.setPayingCardNo(allinpayShopWithdrawCashDTO.getBankCardNo());
        shopWithdrawCash.setPaySysType(PaySysType.ALLINPAY.value());
        this.checkConfig(shopWithdrawCash);
        ShopWallet dbShopWallet = shopWalletService.getShopWalletByShopId(shopId);
        if (shopWithdrawCash.getAmount() > dbShopWallet.getSettledAmount()) {
            // 可提现金额不足
            throw new YamiShopBindException("yami.shop.cash.no.enough");
        }
        // 提现订单支付成功的条件为：status = OK且payStatus = success。
        String bizUserId = AllinpayConstant.SHOP + shopId;
        WithdrawApplyResp withdrawApplyResp = withdrawApply(bizUserId, amount, allinpayShopWithdrawCashDTO.getBankCardNo(), SysTypeEnum.MULTISHOP.value());
        // 保存至数据库，确认支付后更新状态
        String bizOrderNo = withdrawApplyResp.getBizOrderNo();
        shopWithdrawCash.setAllinpayStatus(AllinpayWithdrawCashStatusType.APPLY_SUCCESS.value());
        shopWithdrawCash.setBizOrderNo(bizOrderNo);
        shopWithdrawCash.setShopBankCardId(allinpayShopWithdrawCashDTO.getShopBankCardId());
        // 更新钱包，添加提现日志
        changeWalletAndAddLog(shopWithdrawCash, dbShopWallet);
        return bizOrderNo;
    }

    private WithdrawApplyResp withdrawApply(String bizUserId, Double amount, String bankCardNo, Integer sysType) {
        Integer source = Objects.equals(sysType, SysTypeEnum.ORDINARY.value()) ? VisitSourceType.MOBILE.value() : VisitSourceType.PC.value();
        List<BindCard> bindCards = allinpayCompanyService.queryBankCard(Long.valueOf(bizUserId.substring(AllinpayConstant.SHOP_LENGTH)), bankCardNo);
        if (CollUtil.isEmpty(bindCards)) {
            throw new YamiShopBindException("银行卡不存在");
        }
        BindCard bindCard = bindCards.get(0);
        if (!Objects.equals(bindCard.getBindState(), 1)) {
            throw new YamiShopBindException("银行卡未绑定");
        }
        // 提现单号
        Long payId = segmentService.getSegmentId(SegmentIdKey.ALLINPAY_WITHDRAW_CASH);
        String domainUrl = shopConfig.getDomain().getApiDomainName();
        String backUrl = domainUrl + AllinpayNoticeUrl.WITHDRAW_APPLY;
        // validateType:交易验证方式 0无验证 1短信验证码 2支付密码
        Long validateType = 1L;
        return allinpayManager.withdrawApply(payId, bizUserId, amount, backUrl, bindCard, source, validateType);
    }

    @Override
    public void confirmWithdrawPay(AllinpayShopWithdrawCashDTO shopWithdrawCashDTO, Long shopId) {
        ShopWithdrawCash shopWithdrawCash = shopWithdrawCashMapper.selectOne(new LambdaQueryWrapper<ShopWithdrawCash>()
                .eq(ShopWithdrawCash::getBizOrderNo, shopWithdrawCashDTO.getBizOrderNo()));
        if (Objects.isNull(shopWithdrawCash)) {
            throw new YamiShopBindException("验证码有误或已过期");
        }
        if (!Objects.equals(shopId, shopWithdrawCash.getShopId())) {
            throw new YamiShopBindException("当前提现订单号不属于该店铺");
        }
        if (!Objects.equals(shopWithdrawCash.getAllinpayStatus(), AllinpayWithdrawCashStatusType.APPLY_SUCCESS.value())
                && !Objects.equals(shopWithdrawCash.getAllinpayStatus(), AllinpayWithdrawCashStatusType.WAIT_PAY.value())) {
            throw new YamiShopBindException("申请状态异常，请刷新重试");
        }
        String bizUserId = AllinpayConstant.SHOP + shopId;
        PayByBackSmsResp payByBackSmsResp = allinpayManager.payByBackSms(new PayByBackSmsReq(bizUserId, shopWithdrawCash.getBizOrderNo(), shopWithdrawCashDTO.getVerificationCode()));
        String payFailMessage = payByBackSmsResp.getPayFailMessage();
        String payStatus = payByBackSmsResp.getPayStatus();
        if (Objects.equals(payStatus, AllinpayPayStatus.UNPAY.value())) {
            // 收银宝快捷短信验证码输入错误场景，允许商户继续调用确认支付
            shopWithdrawCash.setAllinpayStatus(AllinpayWithdrawCashStatusType.WAIT_PAY.value());
            shopWithdrawCash.setPayFailMessage(payFailMessage);
            logger.error("提现订单{}提现失败，原因为：{}", payByBackSmsResp.getBizOrderNo(), payFailMessage);
            shopWithdrawCashMapper.updateById(shopWithdrawCash);
        }
    }

    @Override
    public void resendPaySms(String bizOrderNo, Long shopId) {
        ShopWithdrawCash shopWithdrawCash = shopWithdrawCashMapper.selectOne(new LambdaQueryWrapper<ShopWithdrawCash>()
                .eq(ShopWithdrawCash::getBizOrderNo, bizOrderNo));
        if (Objects.isNull(shopWithdrawCash)) {
            throw new YamiShopBindException("提现记录不存在");
        }
        if (!Objects.equals(shopId, shopWithdrawCash.getShopId())) {
            throw new YamiShopBindException("当前提现订单号不属于该店铺");
        }
        if (!Objects.equals(shopWithdrawCash.getAllinpayStatus(), AllinpayWithdrawCashStatusType.WAIT_PAY.value())) {
            throw new YamiShopBindException("提现申请不在未支付状态，请刷新重试");
        }
        ResendPaySmsResp resendPaySmsResp = allinpayService.resendPaySms(bizOrderNo);
        logger.info("订单号{}重发短信验证码至手机{}成功", resendPaySmsResp.getBizOrderNo(), resendPaySmsResp.getPhone());
    }

    private void checkAllinpay(Long shopId, Double amount) {
        if (!allinpayCompanyService.getIsAllinpay()) {
            throw new YamiShopBindException("当前不支持通联提现");
        }
        ShopWithdrawCash shopWithdrawCash = new ShopWithdrawCash();
        shopWithdrawCash.setAmount(amount);
        shopWithdrawCash.setShopId(shopId);
        checkConfig(shopWithdrawCash);
        if (amount < Constant.MIN_PRODUCT_AMOUNT) {
            throw new YamiShopBindException("提现金额不能少于0.01元");
        }
        ShopDetail shopDetail = shopDetailService.getShopDetailByShopId(shopId);
        if (Objects.equals(shopDetail.getIsBindPhone(), 0) ||
                !Objects.equals(shopDetail.getCompanyInfoProcessStatus(), CompanyInfoProcessStatus.SUCCESS.value()) ||
                !Objects.equals(shopDetail.getIdCardCollectProcessStatus(), IdCardCollectProcessStatus.ALL.value())) {
            throw new YamiShopBindException("店铺信息未通过审核，无法提现");
        }
    }

    @Override
    public void withdrawBack(String bizOrderNo, String payStatus, String bizUserId, String payFailMessage) {
        ShopWithdrawCash shopWithdrawCash = shopWithdrawCashMapper.selectOne(new LambdaQueryWrapper<ShopWithdrawCash>()
                .eq(ShopWithdrawCash::getBizOrderNo, bizOrderNo));
        if (Objects.isNull(shopWithdrawCash)) {
            throw new YamiShopBindException("提现记录不存在");
        }
        if (Objects.equals(shopWithdrawCash.getAllinpayStatus(), AllinpayWithdrawCashStatusType.CASH_SUCCESS.value())) {
            return;
        }
        Long shopId = shopWithdrawCash.getShopId();
        Double amount = shopWithdrawCash.getAmount();
        if (Objects.equals(payStatus, AllinpayPayStatus.OK.value())) {
            allinpaySuccess(shopId, shopWithdrawCash, amount);
        } else if (Objects.equals(payStatus, AllinpayPayStatus.ERROR.value())) {
            allinpayFail(shopId, shopWithdrawCash, amount, bizOrderNo, payFailMessage);
        }
        shopWithdrawCashMapper.updateById(shopWithdrawCash);
    }

    private void allinpayFail(Long shopId, ShopWithdrawCash shopWithdrawCash, Double amount, String bizOrderNo, String payFailMessage) {
        shopWithdrawCash.setAllinpayStatus(AllinpayWithdrawCashStatusType.CASH_FAIL.value());
        shopWithdrawCash.setPayFailMessage(payFailMessage);
        logger.error("商家提现订单{}提现失败，原因为：{}", bizOrderNo, payFailMessage);
        ShopWallet dbShopWallet = shopWalletService.getShopWalletByShopId(shopWithdrawCash.getShopId());
        ShopWallet newShopWallet = BeanUtil.map(dbShopWallet, ShopWallet.class);
        // 将冻结的金额返回到已结算金额
        newShopWallet.setSettledAmount(Arith.add(dbShopWallet.getSettledAmount(), amount));
        newShopWallet.setFreezeAmount(Arith.sub(dbShopWallet.getFreezeAmount(), amount));
        // 乐观锁更新钱包信息
        if (!shopWalletService.updateById(newShopWallet)) {
            // 失败则抛异常
            // 服务器繁忙
            throw new YamiShopBindException("yami.network.busy");
        }
        shopWalletLogService.saveShopWalletLog(dbShopWallet, newShopWallet, ShopWalletChangeReason.REFUSE_CASH, null);
    }

    private void allinpaySuccess(Long shopId, ShopWithdrawCash shopWithdrawCash, Double amount) {
        shopWithdrawCash.setAllinpayStatus(AllinpayWithdrawCashStatusType.CASH_SUCCESS.value());
        // 更新店铺结算金额
        ShopWallet dbShopWallet = shopWalletService.getShopWalletByShopId(shopWithdrawCash.getShopId());
        ShopWallet newShopWallet = BeanUtil.map(dbShopWallet, ShopWallet.class);
        // 减去冻结的金额
        newShopWallet.setFreezeAmount(Arith.sub(dbShopWallet.getFreezeAmount(), amount));
        // 乐观锁更新钱包信息
        if (!shopWalletService.updateById(newShopWallet)) {
            // 失败则抛异常
            // 服务器繁忙
            throw new YamiShopBindException("yami.network.busy");
        }
        shopWalletLogService.saveShopWalletLog(dbShopWallet, newShopWallet, ShopWalletChangeReason.PASS_CASH, null);
    }
}
